What
is eXensible Application Markup Language (or XAML)? In Silverlight,
XAML is used to design the user interfaces (both the look and feel of
applications) but it does quite a lot more. The main concept to learn
here is that XAML can be thought of as a serialization format that
works well with tools. It allows us to declare the structure of a user
interface. Declaring the interface in this way makes it easy for tools
to create the user interfaces and have applications consume the files
at runtime.
What do I mean by a serialization format? XAML is quite simple; let’s take a very simple piece of XAML:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBlock Text="Hello" />
<Rectangle Width="100"
Height="100"
Fill="Blue" />
</Grid>
</UserControl>
XAML is an XML file that
obeys basic XML rules (e.g single top-level container, case
sensitivity). In this file we are declaring a UserControl root that contains a GridTextBlock and a Rectangle).
This is a basic hierarchy of this simple user interface. When parsed,
this XAML document is used to create that same hierarchy in memory.
Literally, the name of the element ties itself to the name of a class.
So when the XAML is parsed, the UserControl element informs the system
to create a new UserControl instance. To be used here all the classes must allow for empty constructors (in the .NET sense) so that the UserControl class can be created. After it creates the UserControl itself, it looks at its sub-elements (the Grid) and creates that element as a child inside the UserControl. Finally, it creates the TextBlock and Rectangle and places them as children inside the Grid. When the TextBlock is created, it sees the attribute (Text) and calls the property setter of the new TextBlock with the contents of the attribute. It does this with the multiple attributes of the Rectangle
as well. In this way it uses the XAML to build an in-memory object
graph that follows the same structure as the XAML. Understanding that
the XAML you are using is the basis for your runtime design is very
important in understanding how XAML works. element that contains two elements (a
XAML Object Properties
Most objects’ properties you will set in XAML are simple and string-based:
<Rectangle Fill="Blue" />
Not all properties can be
set using the simple, string-based syntax. Under the covers many
properties (during XAML parsing) are attempting to convert a string
attribute to a property value. For example, Fill is a property that accepts a Brush value, not a color. When Fill=“Blue” is parsed as XAML, there is a conversion done between the string (i.e. “Blue”) and a brush called a SolidColorBrush. For a more complex value type (like a Brush), there is a verbose syntax for setting property values:
<Rectangle>
<Rectangle.Fill>
<SolidColorBrush Color="Blue" />
</Rectangle.Fill>
</Rectangle>
This verbose syntax is identical at runtime as the earlier example. By adding an element inside the Rectangle whose name is the name of the object, a dot and the name of the property (e.g. Rectangle.Fill),
it allows us to define the value for the property using XAML instead of
being stuck using just strings. Since not all complex property values
can be defined in a way that a conversion can be made, this syntax
allows for property values to be set when the value is a complex type
that would be difficult or impossible to describe in a single string.
For example, let’s replace the SolidColorBrush with a LinearGradientBrush:
<Rectangle>
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="White" Offset="0.5" />
<GradientStop Color="Blue" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
In this example we can see
that defining a fill by specifying the colors and offsets would not
only be difficult in a simple string, but would make the XAML even
harder to read. In this way XAML allows you to set very complex
properties without having to invent conversions. You will see how this
is used in many different places in XAML and we continue.
Understanding XAML Namespaces
Inside the root element contains two namespaces. Namespaces in XAML are XML namespaces. The default namespace (xmlns) declares that this is a XAML document. The second namespace (xmlns:x) brings in several that are all prefixed with the x alias. So when you see x:Class that is a convention that is defined in the second namespace.
You can think of the
namespace aliasing as similar to namespaces in .NET. When you add a
namespace, it brings in those new types of things that can be described
in XAML. Unlike .NET though, you have to use an alias (since all other
namespaces are not the ‘default’ namespace) and then use that alias
everywhere you want to refer to information from that namespace. In the
x alias’ case, the alias here as ‘x’ is just a convention that XAML
tends to use. In the XML namespace sense, you can change the alias to
whatever you want but would have to change it everywhere its referenced
as well. For example:
<UserControl foo:Class="WinningTheLottery.Sample"
xmlns="..."
xmlns:foo="...">
The alias is just that. An
alias so that the parser can determine which of the namespaces your
element or attribute is from. When we changed the name of the alias, it
is what you would use ot alias that namespace in the rest of the
document.
While these namespaces
represent the basic XAML namespaces, you can extend the XAML by using
namespaces to bring in arbitrary .NET types as well. If you define a
namespace that points at a .NET namespace and assembly, those types
will be available in the XAML as well:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Grid>
<TextBlock>
<TextBlock.Text>
<sys:String>Hello</sys:String>
</TextBlock.Text>
</TextBlock>
</Grid>
</UserControl>
In this example, the XAML ‘imports’ the System namespace that exists inside the mscorlib.dll
assembly. Once that .NET namespace is imported, all the types in that
namespace are creatable in the XAML. The types that are created in XAML
must conform to the following rules:
If any .NET objects follow
these rules, they are creatable in XAML (and therefore can be part of
your initial object graph). You will see how this is used as we
continue in this chapter.
Naming in XAML
Unlike other platforms, XAML
does not require that every object in the XAML be specifically named.
In fact, it is probably a bad idea to name every object in the XAML.
Naming objects in the XAML becomes important once you need to refer to
an object by name (e.g. from code or other reason). Naming objects in
XAML takes the form of an attribute that can be applied to most XAML
elements: x:Name. For example:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot">
<TextBlock Text="Hello"
x:Name="theTextBlock" />
<Rectangle Width="100"
Height="100"
Fill="Blue"
x:Name="theRectangle" />
</Grid>
</UserControl>
You will notice that
the naming attribute starts with the x: prefix (or alias). As was
explained in the namespaces discussion, this means that attribute is
available through the x namespace that is included on the top of every
XAML document (by default). Once these objects are named, they will be
available to other XAML elements by name or via code (both of which you
will see in this chapter). The names used here must be unique. Each
name can occur only once within a single XAML document. This simplifies
the naming strategy but also means there is no sense of naming scope
(like HTML has).